from multiprocessing import Pool,freeze_support,current_process,active_children,get_start_method,set_start_method,get_context,Lock
import time,os,psutil,threading
# import numpy as np
import atexit,sys,signal,random
_pool=None
try:
    import tool.public_tool
except:
    import public_tool
    
from tool.logging_tool import info_print,warn_print,ppid,pid,app_exit_event

cpu_factor=4
cpu_count = os.cpu_count()  # 获取CPU核心数
def task(*args):
    # info_print(f"父进程ID:{os.getppid()} 当前进程ID:{os.getpid()} name:{current_process().name}")
    return args
pmethod="spawn"
cname=current_process().name
stop=False
def stop_process(pid:int=0):
    try:
        pid=int(pid)
        if pid>0:
            current_process = psutil.Process(pid)
            children = current_process.children(recursive=True)
            warn_print("子进程:",current_process.pid,children)
            try:
                for child in children:
                    # time.sleep(.1)
                    # child.kill()
                    child.terminate()
                    warn_print("停止子进程",child.ppid(),child.pid,ppid,pid)
                    # stop_process(child.pid)
                time.sleep(.1)
            except Exception as e:
                print("关闭进程异常:", str(e))
            finally:
                # if os.getpid()!=current_process.pid:
                warn_print("停止当前进程",pid,current_process.pid,current_process.is_running())
                if current_process.is_running():
                    warn_print('关闭进程:{} {}', current_process.pid, current_process.name())
                    current_process.kill()
                current_process.terminate()
            pass
    except psutil.NoSuchProcess:
        # print("进程关闭成功:", pid)
        pass
# 进程池
class ProcessPool:
    _instance = None
    _context=None
    def __new__(cls):
        global _pool
        if cls._instance is None:
            cls._instance = super().__new__(cls)
            gmethod=get_start_method()
            if pmethod!=gmethod:
                cls._context=get_context(pmethod)
                cls._instance.pool = cls._context.Pool(processes=cpu_factor)
                info_print("进程启动 method:",cls._context)
            else:
                cls._instance.pool = Pool(processes=cpu_factor)
            # cls._instance.pool = Pool(processes=cpu_factor)
            
            _pool=cls._instance
        return cls._instance
    
    def __del__(self):
        info_print("退出Process")
        self.pool.close()
        self.pool.join()
    def hot(self):
        # info_print("子进程预热 start")
        # cls._instance.pool.map_async(task, range(cpu_factor))  # 空\跑预热
        self.pool.map(task, range(cpu_factor))  # 空\跑预热
        # info_print("子进程预热 end")
        pass
    def stop(self):
        # 正确关闭
        warn_print("停止多进程",pid)
        # self.pool.close()  # 禁止提交新任务
        self.pool.terminate()  # 发送 SIGTERM
        self.pool.join()   # 等待所有子进程结束
        
        
    def starmap_async_once(self,fun,*args):
        if stop:
            info_print("主进程关闭,不执行后续进程任务...")
            self.stop()
            return 
        # 异步执行 一次动作
        # fargs=list(args)
        try:
            result = self.pool.starmap_async(fun, [args])
        except Exception as e:
            warn_print("starmap_async_once 异常:", str(e))
            result = None
        # info_print("主进程继续...")
        # info_print("最终结果:", result.get())
        return result
        pass
def cleanup():
    global stop,_pool
    # stop=True
    try:
        if _pool is not None:
            _pool.stop()
            for child in active_children():
                info_print("执行清理：终止子进程...",pid,child.pid)
                child.terminate()
                child.join()
    except:
        warn_print("执行清理：pool 异常",ppid,pid,cname,active_children())
        pass
    info_print("子进程清理完成",pid,cname,active_children())
    # stop_process(pid)
def a_cleanup():
    info_print("atexit",cname)
    cleanup()
def handle_signal(signum, frame):
    global app_exit_event
    app_exit_event.set()
    info_print(f"收到信号 {signum}，准备退出...",ppid,pid,cname)
    # 随机暂停sleep
    try:
        cleanup()
    except Exception as e:
        warn_print("关闭进程异常:", str(e))
    info_print("==============应用退出==============")
    sys.exit(0)
def c_handle_signal(signum, frame):
    time.sleep(random.uniform(0.1, 0.3))
    info_print("c_handle_signal",cname)
    handle_signal(signum, frame)
def t_handle_signal(signum, frame):
    info_print("t_handle_signal",cname)
    handle_signal(signum, frame)
if 'MainProcess'==cname:
    # 注册 atexit 清理
    # 注册信号处理
    pass
# warn_print(f"注册销毁事件",ppid,pid,cname)
# atexit.register(a_cleanup)
try:
    signal.signal(signal.SIGTERM, t_handle_signal)  # Supervisor 默认发送 SIGTERM
    signal.signal(signal.SIGINT, c_handle_signal)   # Ctrl+C 时触发
except:
    warn_print("注册信号处理异常",ppid,pid,cname)
    pass
info_print("启动进程:",cname)
_pool_event=threading.Event()
_pool_event.set()
def get_pool():
    """获取全局进程池"""
    global _pool,_pool_event
    time.sleep(random.uniform(0.1, 0.3))
    # info_print("全局进程池锁 start :",_pool_event.is_set())
    if not _pool_event.is_set():
        # info_print("全局进程池锁定中,等待解锁...")
        # 等待锁定解锁
        _pool_event.wait()
        # info_print("全局进程池解锁完成")
        
    if _pool is None:
        _pool_event.clear()
        try:
            if _pool is None:
                # info_print("创建全局进程池")
                _pool = ProcessPool()
                _pool.hot()
                # info_print("全局进程池创建完成")
        finally:
            _pool_event.set()
    # info_print("全局进程池锁 end:",_pool_event.is_set())
    return _pool
if __name__ == '__main__':
    info_print(f"进程启动 PID:{pid} name:{__name__} 可用CPU核心: {cpu_count} 处理进程:{cpu_factor}")
    pool = ProcessPool()
    # pool.hot()
    # res=process_data(task,[1])
    # print("global_pool:",res)
    # videofile="D:/work/ai/ultralytics/supervision/examples/tracking/tmp/process0/test/out.mp4"
    # convert_to_mp4(videofile,"test.out.mp4")
    info_print("转化完成")
    index=0
    while True:
        print(range(10))
        time.sleep(1)
        if index>10:
            break
        index+=1
    info_print("主进程结束")
    signal.raise_signal(signal.SIGINT)  # 模拟 Ctrl+C 信号
